#include "stdafx.hpp"
#include "ColligereUtils.hpp"
#include "ColligereApp.hpp"

void col::get_webpage ( const wxURI &rUri, wxString &rTo,
								  wxUint32 timeout, wxUint32 port )
{
    wxHTTP http;

	http.SetHeader ( "Accept" , "text/*" );
	http.SetHeader ( "Accept-Encoding", "gzip" );
    http.SetHeader ( "User-Agent", wxGetApp().GetAppName() );
    http.SetTimeout ( timeout );

	wxLogGeneric ( wxLOG_User, _("Connecting to ") + rUri.GetServer() );

	if ( !http.Connect ( rUri.GetServer(), port ) )
	{
		throw std::runtime_error ( protocol_err_to_str ( http.GetError(), rUri ) );
	}
	
	wxLogGeneric ( wxLOG_User, _("Requesting \"%s\" from the server."), rUri.BuildURI() );

	const boost::scoped_ptr < wxInputStream > istream ( http.GetInputStream 
		( rUri.BuildURI() ) );

	if ( !istream  )
	{
		throw std::runtime_error ( protocol_err_to_str ( http.GetError(), rUri ) );
	}
	
	if ( http.GetHeader ( "Content-Encoding" ) == "gzip" )
	{
		wxZlibInputStream zin ( *istream );
		wxStringOutputStream ostream ( &rTo );
		zin.Read ( ostream );
	}
	else
	{
		wxStringOutputStream ostream ( &rTo );
		istream->Read ( ostream );
	}
}

const wxString col::protocol_err_to_str ( wxProtocolError err, const wxURI &rUri )
{
	using namespace boost;
	switch ( err )
	{
	case wxPROTO_NETERR: 
		return str ( format ( "An unknown network error has occurred.\n\nAddress: %s" ) %
			rUri.BuildURI() );
	case wxPROTO_PROTERR: 
		return str ( format ( "An error has occurred during negotiation.\n\nAddress: %s" ) %
			rUri.BuildURI() );
	case wxPROTO_CONNERR: 
		return str ( format ( "Unable to connect to the server.\n\nAddress: %s" ) % 
			rUri.BuildURI() );
	case wxPROTO_INVVAL: 
		return str ( format ( "Invalid value.\n\nAddress: %s" ) % 
			rUri.BuildURI() );
	case wxPROTO_NOFILE: 
		return str ( format ( "The remote file doesn't exist.\n\nAddress: %s" ) % 
			rUri.BuildURI() );
	case wxPROTO_ABRT: 
		return str ( format ( "Last action aborted.\n\nAddress: %s" ) % 
			rUri.BuildURI() );
	case wxPROTO_RCNCT: 
		return str ( format ( "An error has occured during reconnection.\n\nAddress: %s" ) % 
			rUri.BuildURI() );
	case wxPROTO_STREAMING: 
		return str ( format ( "Someone tried to send a command during a transfer.\n\nAddress: %s" ) %
			rUri.BuildURI() );
	default:
		return str ( format ( "An unknown network error occurred.\n\nAddress: %s" ) %
			rUri.BuildURI() );
	}
}

void col::capitalize ( wxString &rStr )
{
	wxString::iterator it ( rStr.begin() );

	if ( it != rStr.end() )
	{
		rStr[0] = std::toupper ( ( unsigned char ) rStr[0] );
	}
	while ( ++it != rStr.end() )
	{
		*it = tolower ( ( unsigned char ) *it );
	}
}

const wxString col::capitalize ( const wxString &rStr )
{
	wxString cpy ( rStr );
	capitalize ( cpy );
	return cpy;
}

bool col::compress_file ( const wxString &rInFile, const wxString &rOutFile,
						 wxUint32 compressionLevel )
{
	wxASSERT ( compressionLevel > 0 );

	wxLogDebug ( "Compressing the file \"%s\" with the compression level of %d. "\
		"Output file: %s.", rInFile, compressionLevel, rOutFile );

	wxFileInputStream file_in ( rInFile );

	if ( !file_in.IsOk() )
	{
		wxLogDebug ( "Unable to open the file \"%s\".", rInFile );
		return false;
	}

	wxFileOutputStream file_out ( rOutFile );

	if ( !file_out.IsOk() )
	{
		wxLogDebug ( "Unable to open the file \"%s\".", rOutFile );
		return false;
	}
	return wxZlibOutputStream ( file_out, 
		compressionLevel ).Write ( file_in ).LastWrite() != 0;
}

bool col::decompress_file ( const wxString &rInFile, const wxString &rOutFile )
{
	wxLogDebug ( "Decompressing the file \"%s\". Output file: %s.", rInFile, rOutFile );

	wxFileInputStream file_in ( rInFile );

	if ( !file_in.IsOk() )
	{
		wxLogDebug ( "Unable to open the file \"%s\".", rInFile );
		return false;
	}

	wxFileOutputStream file_out ( rOutFile );

	if ( !file_out.IsOk() )
	{
		wxLogDebug ( "Unable to open the file \"%s\".", rOutFile );
		return false;
	}
	return wxZlibInputStream ( file_in ).Read ( file_out ).LastRead() != 0;
}

const wxString col::gui::get_prop_grid_value ( long ctrl_id,
												 long parent_id,
												 const wxString &name )
{
	if ( const wxWindow *win = find_window ( ctrl_id, parent_id ) )
	{
		if ( const wxPropertyGrid *pg = wxDynamicCast ( win,
			wxPropertyGrid ) )
		{
			const wxPGProperty *p = pg->GetProperty ( name );
			return p ? p->GetValueAsString() : empty_string;
		}
	}
	return empty_string;
}

const wxString col::gui::get_ctrl_value ( long ctrl_id, long parent_id )
{
	if ( const wxWindow *win = find_window ( ctrl_id, parent_id ) )
	{
		// wxComboBox must be checked before wxControlWithItems.
		// This is because wxControlWithItems only provides the 
		// GetStringSelection method which returns the correct 
		// string only if the string is already in the control.
		if ( const wxComboBox *cb = dynamic_cast < const wxComboBox * > ( win ) )
		{
			return cb->GetValue();
		}
		else if ( const wxControlWithItems *cwi = dynamic_cast 
			< const wxControlWithItems * > ( win ) )
		{
			return cwi->GetStringSelection();
		}
		else if ( const wxTextCtrl *tc = wxDynamicCast ( win, wxTextCtrl ) )
		{
			return tc->GetValue();
		}
		else if ( const wxCheckBox *cb = wxDynamicCast ( win, wxCheckBox ) )
		{
			return wxString() << cb->GetValue();
		}
		else if ( const wxSpinCtrl *sc = wxDynamicCast ( win, wxSpinCtrl ) )
		{
			return wxString() << sc->GetValue();
		}
	}
	return empty_string;
}

void col::gui::set_ctrl_value ( long ctrl_id, long parent_id, const wxString &val )
{
	if ( val.empty() ) return;

	if ( wxWindow *win = find_window ( ctrl_id, parent_id ) )
	{
		if ( wxTextCtrl *tc = wxDynamicCast ( win, wxTextCtrl ) )
		{
			tc->ChangeValue ( val );
		}
		else if ( wxComboBox *cb = dynamic_cast < wxComboBox * > ( win ) )
		{
			cb->SetValue ( val );
		}
		else if ( wxControlWithItems *cwi = dynamic_cast 
			< wxControlWithItems * > ( win ) )
		{
			cb->SetStringSelection ( val );
		}
		else if ( wxCheckBox *cb = wxDynamicCast ( win, wxCheckBox ) )
		{
			cb->SetValue ( val == "1" );
		}
		else if ( wxSpinCtrl *sc = wxDynamicCast ( win, wxSpinCtrl ) )
		{
			sc->SetValue ( val );
		}
	}
}

wxWindow *col::gui::find_window ( long id, long parent_id )
{
	if ( wxWindow *parent = wxWindow::FindWindowById ( parent_id ) )
	{
		if ( wxWindow *win = wxWindow::FindWindowById ( id, parent ) )
		{
			return win;
		}
	}
	return 0;
}